﻿using S7Cat.Models;
using System.Numerics;

namespace S7Cat.Tools
{
    public static class PoolExtensions
    {
        #region Read
        public static async Task<T> ReadAsync<T>(this ConnectionPool pool, DataItemAddress address, CancellationToken cancellationToken = default) where T : unmanaged, INumber<T>
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            return await plc.ReadAsync<T>(address, cancellationToken).ConfigureAwait(false);
        }

        public static async Task<bool> ReadAsync(this ConnectionPool pool, DataItemAddress address, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            return await plc.ReadAsync(address, cancellationToken).ConfigureAwait(false);
        }

        public static async Task<T> ReadStructAsync<T>(this ConnectionPool pool, DataItemAddress address, CancellationToken cancellationToken = default) where T : struct, IPlcStruct<T>
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            return await plc.ReadStructAsync<T>(address, cancellationToken).ConfigureAwait(false);
        }

        public static async Task<byte[]> ReadBytesAsync(this ConnectionPool pool, DataItemAddress address, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            return await plc.ReadBytesAsync(address, cancellationToken).ConfigureAwait(false);
        }

        public static async Task<MultipleReader> ReadMultipleReaderAsync(this ConnectionPool pool, Memory<DataItemAddress> addresses, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            return await plc.ReadMultipleReaderAsync(addresses, cancellationToken).ConfigureAwait(false);
        }




        public static async Task<T> ReadAsync<T>(this ConnectionPool pool, string address, CancellationToken cancellationToken = default) where T : unmanaged, INumber<T>
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            return await plc.ReadAsync<T>(AddressParser.Parse(address), cancellationToken).ConfigureAwait(false);
        }

        public static async Task<bool> ReadAsync(this ConnectionPool pool, string address, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            return await plc.ReadAsync(AddressParser.Parse(address), cancellationToken).ConfigureAwait(false);
        }

        public static async Task<T> ReadStructAsync<T>(this ConnectionPool pool, string address, CancellationToken cancellationToken = default) where T : struct, IPlcStruct<T>
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            return await plc.ReadStructAsync<T>(AddressParser.Parse(address), cancellationToken).ConfigureAwait(false);
        }

        public static async Task<byte[]> ReadBytesAsync(this ConnectionPool pool, string address, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            return await plc.ReadBytesAsync(AddressParser.Parse(address), cancellationToken).ConfigureAwait(false);
        }
        #endregion


        #region Write
        public static async Task WriteBytesAsync(this ConnectionPool pool, DataItemAddress address, Memory<byte> bytes, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            await plc.WriteBytesAsync(address, bytes, cancellationToken).ConfigureAwait(false);
        }

        public static async Task WriteAsync<T>(this ConnectionPool pool, DataItemAddress address, T value, CancellationToken cancellationToken = default) where T : unmanaged, INumber<T>
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            await plc.WriteAsync(address, value, cancellationToken).ConfigureAwait(false);
        }

        public static async Task WriteAsync(this ConnectionPool pool, DataItemAddress address, bool value, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            await plc.WriteAsync(address, value, cancellationToken).ConfigureAwait(false);
        }

        public static async Task WriteStructAsync<T>(this ConnectionPool pool, DataItemAddress address, T value, CancellationToken cancellationToken = default) where T : struct, IPlcStruct<T>
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            await plc.WriteStructAsync(address, value, cancellationToken).ConfigureAwait(false);
        }

        public static async Task WriteMultipleWriterAsync(this ConnectionPool pool, MultipleWriter writer, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            await plc.WriteMultipleWriterAsync(writer, cancellationToken).ConfigureAwait(false);
        }




        public static async Task WriteBytesAsync(this ConnectionPool pool, string address, Memory<byte> bytes, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            await plc.WriteBytesAsync(AddressParser.Parse(address), bytes, cancellationToken).ConfigureAwait(false);
        }

        public static async Task WriteAsync<T>(this ConnectionPool pool, string address, T value, CancellationToken cancellationToken = default) where T : unmanaged, INumber<T>
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            await plc.WriteAsync(AddressParser.Parse(address), value, cancellationToken).ConfigureAwait(false);
        }

        public static async Task WriteAsync(this ConnectionPool pool, string address, bool value, CancellationToken cancellationToken = default)
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            await plc.WriteAsync(AddressParser.Parse(address), value, cancellationToken).ConfigureAwait(false);
        }

        public static async Task WriteStructAsync<T>(this ConnectionPool pool, string address, T value, CancellationToken cancellationToken = default) where T : struct, IPlcStruct<T>
        {
            using var plc = await pool.GetAvailableAsync(cancellationToken).ConfigureAwait(false);
            await plc.WriteStructAsync(AddressParser.Parse(address), value, cancellationToken).ConfigureAwait(false);
        }
        #endregion
    }
}
